//
//  YFRefreshControl.swift
//  YFSwiftWeibo
//
//  Created by tsaievan on 2017/9/12.
//  Copyright © 2017年 tsaievan. All rights reserved.
//

import UIKit

///< 先定义一个临界点, 如果超出,就更改状态
fileprivate let YFRefreshContentOffset: CGFloat = 200



///< 自定义刷新控件
class YFRefreshControl: UIControl {
    
    fileprivate weak var scrollView: UIScrollView?
    
    lazy var refreshView = YFRefreshView.refreshView()
    
    init() {
        super.init(frame: CGRect())
        setupUI()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupUI()
    }
    
    override func willMove(toSuperview newSuperview: UIView?) {
        super.willMove(toSuperview: newSuperview)
        
        ///< 记录父视图
        guard let sv = newSuperview as? UIScrollView else {
            return
        }
        
        scrollView = sv
        ///< 给父视图添加观察者
        scrollView?.addObserver(self, forKeyPath: "contentOffset", options: [], context: nil)
    }
    
    override func removeFromSuperview() {
        ///< 加观察者从父视图中移除
        superview?.removeObserver(self, forKeyPath: "contentOffset")
        
        ///< 调super要放到后面去调
        super.removeFromSuperview()
    }
    
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        
        guard let sv = scrollView else {
            return
        }
        let height = -(sv.contentInset.top + sv.contentOffset.y)
        ///< 进行判断
        if height < 0 { // 这里直接return. 因为往上推根本不需要做任何事情
            return
        }
        self.frame = CGRect(x: 0, y: -height, width: sv.bounds.width, height: height)
        
        if sv.isDragging { ///< 这里表示, 正在拽的状态
            if height > YFRefreshContentOffset && refreshView.state == .Normal { ///< 拉过了临界点
                ///< 将状态改成正在下拉
                refreshView.state = .Pulling
            }else if height < YFRefreshContentOffset && refreshView.state == .Pulling {
                refreshView.state = .Normal
            }
            ///< 在这里将高度的值传到子控件中
            ///< 如果状态是正在刷新, 那么就不传入高度
            if refreshView.state != .Refreshing {
                refreshView.pullingHeight = height
            }
        }else { ///< 这里表示放手的状态
            if refreshView.state == .Pulling { ///< 表示刷新控件是拉过了临界点之后放手的
                //                ///< 修改刷新状态为正在刷新
                //                refreshView.state = .Refreshing
                //                ///< 将tableView的contentInset改大, 这样刷新了之后,refreshView就可以看得到
                //                /**
                //                 * 这里有一点需要注意的是:
                //                 * 因为刷新控件的frame是根据contentInset.top和contentOffset.y 共同决定的
                //                 * 所以就算当改变了contentInset.top, 那么此时contentOffset.y也对应地改变了, 那么height就必定为0
                //                 * 而之前由于设置了clipToBounds = true, 所以就看不到控件了
                //                 * 所以还要在setupUI()函数里面把那句代码注释掉
                //                 */
                //                var inset = sv.contentInset
                //                inset.top += YFRefreshContentOffset
                //                sv.contentInset = inset
                ///< 这里直接来一句beginRefreshing()
                beginRefreshing()
                sendActions(for: .valueChanged)
            }
        }
    }
    
    func beginRefreshing() {
        print("开始刷新")
        guard let sv = scrollView else {
            return
        }
        
        ///< 在开始改状态之前先来一个判断
        ///< 如果正在刷新, 那么直接retrun
        if refreshView.state == .Refreshing {
            return
        }
        
        ///< 更改刷新状态
        refreshView.state = .Refreshing
        
        ///< 修改contentInset
        var inset = sv.contentInset
        inset.top += YFRefreshContentOffset
        sv.contentInset = inset
        ///< 这里设置一下拉伸的高度
        refreshView.pullingHeight = YFRefreshContentOffset
    }
    
    func endRefreshing() {
        print("结束刷新")
        
        guard let sv = scrollView else {
            return
        }
        ///< 0. 需要做一个判断, 如果不处于刷新状态就直接return
        ///< 注意, 是"不"处于刷新状态
        if refreshView.state != .Refreshing {
            return
        }
        
        ///< 1. 更改状态
        refreshView.state = .Normal
        
        ///< 2. 更改contentInset, 隐藏回去
        var inset = sv.contentInset
        inset.top -= YFRefreshContentOffset
        UIView.animate(withDuration: 0.25) {
            sv.contentInset = inset
        }
    }
}


extension YFRefreshControl {
    fileprivate func setupUI() {
        backgroundColor = superview?.backgroundColor
        ///< 超出父视图的部分不显示
        //        clipsToBounds = true
        addSubview(refreshView)
        
        ///< 使用自动布局
        /**
         * 使用自动布局需要注意的点
         * 首先, 要将'translatesAutoresizingMaskIntoConstraints'禁用
         * 其次, 设置xib控件的自动布局, 需要制定宽高约束
         */
        refreshView.translatesAutoresizingMaskIntoConstraints = false
        
        addConstraint(NSLayoutConstraint(item: refreshView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0))
        
        addConstraint(NSLayoutConstraint(item: refreshView, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 0))
        
        addConstraint(NSLayoutConstraint(item: refreshView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: refreshView.bounds.width))
        
        addConstraint(NSLayoutConstraint(item: refreshView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: refreshView.bounds.height))
    }
}
